package com.zzyk.main.utils;

import com.alibaba.fastjson.JSON;
import com.zzyk.main.model.pojo.HttpHelper;
import org.apache.http.Header;
import org.apache.http.HttpException;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Http请求工具类
 */
public class HttpUtils {

    private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
    private static final String CONTENT_TYPE_NAME = "Content-Type";
    private static final String JSON_CONTENT_TYPE = "application/json";

    private static final String GET = "GET";
    private static final String POST = "POST";

    public static String request(String url, String method, HttpHelper httpHelper) throws HttpException, IOException {
        HttpRequestBase request = null;
        CloseableHttpClient client = null;
        Map<String, String> params = null;
        Map<String, String> headers = null;
        try {
            if (httpHelper != null) {
                params = httpHelper.getParams();
                headers = httpHelper.getHeaders();
                if (httpHelper.getUsername() != null) {
                    client = createClient(httpHelper.getUsername(), httpHelper.getPassword());
                } else {
                    client = createClient();
                }
            } else {
                client = createClient();
            }
            try {
                switch (method) {
                    case GET:
                        request = setGetParams(url, params);
                        break;
                    case POST:
                        request = setPostParams(url, headers);
                        break;
                    default:
                        throw new HttpException("不支持的方法");
                }
            } catch (URISyntaxException e) {
                throw new IOException(e.getMessage(), e);
            }
            setHeader(request, headers);
            try (CloseableHttpResponse response = client.execute(request)) {
                return getResult(response);
            }
        } finally {
            if (client != null) {
                client.close();
            }
        }
    }

    private static CloseableHttpClient createClient() {
        return HttpClientBuilder.create().build();
    }

    private static CloseableHttpClient createClient(String username, String password) {
        HttpClientBuilder builder = HttpClientBuilder.create();
        CredentialsProvider provider = new BasicCredentialsProvider();
        AuthScope scope = new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM);
        UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password);
        provider.setCredentials(scope, credentials);
        builder.setDefaultCredentialsProvider(provider);
        return builder.build();
    }

    private static HttpGet setGetParams(String url, Map<String, String> params) throws URISyntaxException {
        URIBuilder uriBuilder = new URIBuilder(url);
        if (params != null) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                uriBuilder.setParameter(entry.getKey(), entry.getValue());
            }
        }
        return new HttpGet(uriBuilder.build());
    }

    private static HttpPost setPostParams(String url, Map<String, String> params) {
        HttpPost post = new HttpPost(url);
        if (params != null) {
            StringEntity entity = new StringEntity(JSON.toJSONString(params), DEFAULT_CHARSET);
            entity.setContentType(JSON_CONTENT_TYPE);
            post.setEntity(entity);
        }
        return post;
    }

    private static void setHeader(HttpRequestBase requestBase, Map<String, String> headers) {
        if (headers != null) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                requestBase.setHeader(entry.getKey(), entry.getValue());
            }
        }
    }

    private static String getResult(HttpResponse response) throws IOException, HttpException {
        String _charset = getCharset(response);
        Charset charset;
        if (_charset == null) {
            charset = DEFAULT_CHARSET;
        } else {
            charset = Charset.forName(_charset.split(",")[0]);
        }

        if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            return EntityUtils.toString(response.getEntity(), charset);
        } else {
            int code = response.getStatusLine().getStatusCode();
            String message = response.getEntity().toString();
            throw new HttpException(code + " " + message);
        }
    }

    private static String getCharset(HttpResponse response) {
        Header contentType = response.getFirstHeader(CONTENT_TYPE_NAME);

        String regex = "charset=(.*)";

        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(contentType.getValue());
        if (m.find()) {
            return m.group(1);
        } else {
            return null;
        }
        /*for (Header header : response.getAllHeaders()) {
            StringBuffer buffer = new StringBuffer(header.getName());
            buffer.append(": [").append(header.getValue()).append("]");
            System.out.println(buffer);
        }*/
    }


    public static String doPost(String host, String param, String auth, Charset charset) throws MalformedURLException {
        URL url = new URL(host);
        HttpURLConnection conn = null;
        try {
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(30 * 1000);
            conn.setReadTimeout(10 * 1000);
            conn.setDoInput(true);
            conn.setDoOutput(true);
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setRequestProperty("Authorization", "Basic " + auth);
            try (OutputStream out = conn.getOutputStream();
                 OutputStreamWriter writer = new OutputStreamWriter(out, charset)) {
                writer.write(param);
                writer.flush();
                return getResponse(conn, charset);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } finally {
            System.out.println("END");
        }
    }

    public static String doGet(String host, String auth, Charset charset) throws MalformedURLException {
        URL url = new URL(host);
        HttpURLConnection conn = null;
        try {
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(30 * 1000);
            conn.setReadTimeout(10 * 1000);
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setRequestProperty("Authorization", "Basic " + auth);
            conn.connect();
            return getResponse(conn, charset);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } finally {
            System.out.println("END");
        }
    }

    private static String getResponse(HttpURLConnection conn, Charset charset) throws IOException {
        if (conn.getResponseCode() == 200) {
            StringBuffer result = new StringBuffer();
            try (InputStream in = conn.getInputStream();
                 BufferedReader reader = new BufferedReader(new InputStreamReader(in, charset))) {
                String line = null;
                while ((line = reader.readLine()) != null) {
                    result.append(line);
                }
            }
            return result.toString();
        } else {
            try (InputStream in = conn.getErrorStream();
                 BufferedReader reader = new BufferedReader(new InputStreamReader(in, charset))) {
                String line = null;
                while ((line = reader.readLine()) != null) {
                    System.out.println(line);
                }
            }
            return null;
        }
    }
}
